# -*- coding:utf-8 -*-
import tkinter as tk
import tkinter.filedialog,tkinter.messagebox
from tkinter import ttk
import os,hashlib,sys

from dpi_fitting import dpi_fitting

HELP_TITLE = '安装帮助'
AES_TITLE = 'AES加解密小工具'

class Help(object):
    '''为安装AES库提供（硬编码的）帮助'''
    
    page1 = ['''          您的电脑尚未安装AES库。我们可以帮助您进行安装。
          如果不需要该帮助，请点击“关闭”键\n\n''',
             '''          1.打开cmd或powershell窗口：\n''',
             '''                        点击下方按钮来打开''',
              '                 2.安装AES包\n',
             '       输入以下指令来安装：（可以直接复制）\n',
             '\n\n       待显示“successfully installed ”时重启本程序',
            ]

    
    def __init__(self):
        self.root = tk.Tk()
        dpi_fitting(self.root)
        self.root.title(HELP_TITLE)         #防止硬编码标题，到时候想改个名字就…

        self.text = tk.Text(self.root)
        self.btframe = tk.Frame(self.root)      #存放“上一步”“下一步”的框架
        ttk.Button(self.btframe,text = '关闭',command = self.root.destroy).pack()

        self.text.pack()
        self.btframe.pack()

        self.loadfile()

    def loadfile(self):
        '''加载帮助内容'''
        button1 = ttk.Button(self.text,text = '打开命令提示符',command = self.opencmd)
        button2 = ttk.Button(self.text,text = '打开powershell',command = self.openpowershell)
        s = tk.StringVar(value = 'pip install pycryptodome')
        entry = tk.Entry(self.text,textvariable = s,width = 22)
        
        for index,one in enumerate(self.page1):
            one += '\n'
            self.text.insert('end',one)
            if index == 2:
                self.text.insert(tk.END,'                ')
                self.text.window_create(tk.END,window = button1)
                self.text.insert(tk.END,'                 ')
                self.text.window_create(tk.END,window = button2)
                self.text.insert(tk.END,'\n\n')
            if index == 4:
                self.text.insert(tk.END,'                        ')
                self.text.window_create(tk.END,window = entry)

        self.text.tag_add('tag1',1.0,'1.end')
        self.text.tag_configure('tag1',foreground = 'orange',font = ('宋体',12))
        self.text.tag_add('title1',5.0,'5.end')
        self.text.tag_configure('title1',foreground = '#8000ff',font = ('楷体',15))
        self.text.tag_add('title2',10.0,'10.end')
        self.text.tag_configure('title2',foreground = '#8000ff',font = ('楷体',15))

        self.text.configure(state = 'disable')

        self.root.mainloop()

    def opencmd(self):
        from multiprocessing import Process
        p = Process(target = os.system,args = ('cmd',))
        p.daemon = True
        p.start()

    def openpowershell(self):
        from multiprocessing import Process
        p = Process(target = os.system,args = ('powershell',))
        p.daemon = True
        p.start()
        

class MainAPP(object):
    '''主程序——一个文件加解密小工具'''
    def __init__(self):      
        self.main = tk.Tk()
        dpi_fitting(self.main)
        self.main.title(AES_TITLE)

        #主标题效果
        self.titleframe = tk.Frame(self.main)
        tk.Label(self.titleframe,text='AES加解密GUI',font = ('楷体',25, 'bold'),fg = 'red', height=2).pack()
        self.titleframe.pack()

        #操作按钮
        self.btframe = tk.Frame(self.main)
        ttk.Button(self.btframe,text = '加密',command = self.cryptopage).pack()
        ttk.Button(self.btframe,text = '解密',command = lambda: self.cryptopage(False)).pack(pady = 10)
        self.btframe.pack(pady = 30)
        self.hastp = False

    def cryptopage(self,en = True):
        '''构建加解密的界面,en为True表示加密,en为False表示解密'''
        def cstate(state):
            state = 'normal' if state else 'disable'

            b.configure(state = state)
            e.configure(state = state)
            c.configure(state = state)
        
        OP = '加密' if en else '解密'
        if self.hastp:return

        self.hastp = True
        
        self.tp = tk.Toplevel(self.main)
        self.tp.title(f'{OP}文件')
        self.tp.protocol('WM_DELETE_WINDOW',self.cancel)
        
        iframe = ttk.LabelFrame(self.tp,relief = 'ridge',borderwidth = 3,text='选择文件')
        tk.Label(iframe,text = f'选择要{OP}的文件').pack(anchor = 'nw')
        self.istring = tk.StringVar()

        choframe = tk.Frame(iframe)
        tk.Entry(choframe,textvariable = self.istring,width = 30).pack(side = 'left')
        ttk.Button(choframe,command = self.chooseinfile,text = '浏览…').pack(side = 'right')
        choframe.pack()

        iframe.pack(pady = 10)

        oframe = ttk.LabelFrame(self.tp,text='选择输出方式',relief = 'groove',borderwidth = 3)
        #tk.Label(oframe,text = '请选择输出文件方式').pack(anchor = 'nw')
        self.och1 = tk.IntVar(value=1)
        ttk.Radiobutton(oframe,text = '覆盖原文件',variable = self.och1,value = 0,command = lambda: cstate(False)).pack()

        cho2frame = tk.Frame(oframe)
        r = ttk.Radiobutton(cho2frame,text = '输出为新文件',variable = self.och1,value = 1,command = lambda:cstate(True))
        r.pack()
        self.ostring = tk.StringVar()
        e = tk.Entry(cho2frame,textvariable = self.ostring,width = 30)
        e.pack(side = 'left')
        b = ttk.Button(cho2frame,text = '浏览…',command = self.chooseoutfile)
        b.pack(side = 'right')
        self.och2 = tk.IntVar()
        c = ttk.Checkbutton(oframe,text = f'{OP}后删除原文件',variable = self.och2)
        cho2frame.pack()
        c.pack()
        oframe.pack(pady = 20)

        self.pw = tk.StringVar()
        color = 'lightblue' if en else '#ff9ff3'
        pwframe = tk.Frame(self.tp,highlightthickness = 5,highlightcolor = color)
        tk.Label(pwframe,text = '请输入密码：').pack(side = 'left')
        tk.Entry(pwframe,textvariable = self.pw,show = '*').pack(side = 'right')
        pwframe.pack(pady = 15)
        
        btframe = tk.Frame(self.tp)
        ttk.Button(btframe,text = '确定',command = lambda: self.confirm(en)).pack(side = 'left')
        ttk.Button(btframe,text = '取消',command = self.cancel).pack(side = 'right')
        btframe.pack(pady = 10)

        self.main.wait_window(self.tp)

    def confirm(self,en = True):
        istring = self.istring.get()
        ostring = self.ostring.get()
        pw = self.pw.get()
        cho = self.och1.get()
        if not istring or (not ostring and cho) or not pw:
            tk.messagebox.showinfo('提示','要填写完整哦')
            return

        if en:
            self.encrypto()
        else:
            try:
                self.decrypto()
            except ValueError:
                tk.messagebox.showwarning('提示','密码不正确！')
                return

        self.tp.destroy()
        self.hastp = False

    def encrypto(self):
        istring = self.istring.get()
        ostring = self.ostring.get()
        pw = self.pw.get()
        with open(istring,'rb') as f:
            text = []
            for one in f:
                text.append(one)
            text = b''.join(text)

        text = encrypt(pw,text)

        och1 = self.och1.get()
        if not och1:
            with open(istring,'wb') as f:
                f.write(text)
        else:
            with open(ostring,'wb') as f:
                f.write(text)

        och2 = self.och2.get()
        if och2:
            os.remove(istring)

    def decrypto(self):
        istring = self.istring.get()
        ostring = self.ostring.get()
        pw = self.pw.get()
        with open(istring,'rb') as f:
            text = []
            for one in f:
                text.append(one)
            text = b''.join(text)

        text = decrypt(pw,text)

        och1 = self.och1.get()
        if not och1:
            with open(istring,'wb') as f:
                f.write(text)
        else:
            with open(ostring,'wb') as f:
                f.write(text)

        och2 = self.och2.get()
        if och2:
            os.remove(istring)
        

    def cancel(self):
        self.hastp = False
        self.tp.destroy()
        
        self.och1.set('')
        self.och2.set('')
        self.istring.set('')
        self.ostring.set('')
        self.pw.set('')

    def chooseinfile(self):
        name = tk.filedialog.askopenfilename(filetypes = [('All files','*.*')])
        self.tp.focus()
        if not name:return
        self.filetype = '.'+os.path.split(name)[1].split('.')[-1]
        self.istring.set(name)

    def chooseoutfile(self):
        if not hasattr(self,'filetype'):
            self.filetype = '.*'
            
        name = tk.filedialog.asksaveasfilename(filetypes = [('The file type you chose','*'+self.filetype),
                                                            ('All files','*.*')],
                                               defaultextension = self.filetype)
        self.tp.focus()
        if not name:return
        self.ostring.set(name)

    def start(self):
        self.main.mainloop()


def to16(text):
    try:
        text = text.encode()
    except AttributeError:
        if isinstance(text,bytes):
            pass
        else:
            return
    while len(text) % 16 != 0:
        text += b'\x00'
    return text


def MD5(text):
    hash = hashlib.md5()
    hash.update(text.encode())
    return hash.digest()


def encrypt(password,text):
    '''加密一段文本'''
    aes = AES.new(to16(password),mode = AES.MODE_ECB)
    secret = aes.encrypt(to16(text))
    pw = MD5(password)

    return pw+b'\x0ced'+secret

def decrypt(password,text):
    '''解密一段文本'''
    text = text.split(b'\x0ced',1)
    if text[0] != MD5(password):
        raise ValueError
        
    aes = AES.new(to16(password),mode = AES.MODE_ECB)
    light = aes.decrypt(text[1]).rstrip(b'\x00')
    return light



if __name__ == '__main__':
    try:
        from Crypto.Cipher import AES
    except ImportError:
        Help()      #帮助安装AES加密库
        sys.exit()
        
    MainAPP().start()
